
// RGB ~ LUM
float rgb2lum (vec3 RGB) {
    const vec3 W = vec3(0.299, 0.587, 0.114);
    return dot(RGB, W);
}

// RGB ~ YUV
vec3 rgb2yuv (vec3 RGB) {
    const mat4 M = mat4(
        +0.2990, -0.1690, +0.4990, +0.0000,
        +0.5870, -0.3310, -0.4180, +0.0000,
        +0.1140, +0.4990, -0.0813, +0.0000,
        +0.0000, +0.5000, +0.5000, +0.0000
    );
    vec4 YUV = M * vec4(RGB, 1.0);
    return YUV.xyz;
}
vec3 yuv2rgb (vec3 YUV) {
    const mat4 M = mat4(
        +1.000, +1.000, +1.000, +0.000,
        +0.000, -0.344, +1.772, +0.000,
        +1.402, -0.714, +0.000, +0.000,
        -0.701, +0.529, -0.886, +0.000
    );
    vec4 RGB = M * vec4(YUV, 1.0);
    return RGB.rgb;
}

// RGB ~ HSV
vec3 rgb2hsv (vec3 RGB) {
    const vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(RGB.bg, K.wz), vec4(RGB.gb, K.xy), step(RGB.b, RGB.g));
    vec4 q = mix(vec4(p.xyw, RGB.r), vec4(RGB.r, p.yzx), step(p.x, RGB.r));
    float d = q.x - min(q.w, q.y);
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + 1.0e-10)), d / (q.x + 1.0e-10), q.x);
}
vec3 hsv2rgb (vec3 HSV) {
    const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(HSV.xxx + K.xyz) * 6.0 - K.www);
    return HSV.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), HSV.y);
}

// RGB ~ HSL
vec3 rgb2hsl (vec3 RGB) {
    float cmin = min(RGB.r, min(RGB.g, RGB.b));
    float cmax = max(RGB.r, max(RGB.g, RGB.b));
    float C = cmax - cmin;
    float Ceq0 = step(C, 0.0);
    float Cgt0 = 1.0 - Ceq0;

    vec3 H3 = (RGB.gbr - RGB.brg) / (C + Ceq0);
    H3 = (H3 + vec3(0.0, 2.0, 4.0)) / 6.0;

    float L2 = cmax + cmin;
    float L2eq0 = step(L2, 0.0);
    float L2eq2 = step(2.0, L2);

    float H = H3.z;
    float S = mix(C / (L2 + L2eq0), C / (2.0 - L2 + L2eq2), step(1.0, L2));
    float L = L2 * 0.5;

    H = mix(H, H3.y, step(cmax, RGB.g));
    H = mix(H, H3.x, step(cmax, RGB.r));
    H = fract(H);
    H *= Cgt0;
    S *= Cgt0;
    return vec3(H, S, L);
}
vec3 hsl2rgb (vec3 HSL) {
    vec3 P = clamp(abs(mod(HSL.xxx * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
    return HSL.zzz + HSL.yyy * (P - 0.5) * (1.0 - abs(HSL.z + HSL.z - 1.0));
}
